package com.hhkj.api.student.service.biz.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.hhkj.admin.course.domain.CourseBankType;
import com.hhkj.admin.course.model.dopo.CourseBankTypeDo;
import com.hhkj.admin.course.model.dopo.CourseBankTypePo;
import com.hhkj.admin.course.model.dopo.CourseDo;
import com.hhkj.admin.course.model.dopo.CoursePo;
import com.hhkj.admin.course.service.base.CourseBankTypeService;
import com.hhkj.admin.course.service.base.CourseService;
import com.hhkj.admin.student.common.cont.StudentConst;
import com.hhkj.admin.student.common.utils.StudentUtils;
import com.hhkj.admin.student.domain.Student;
import com.hhkj.admin.student.domain.StudentCourse;
import com.hhkj.admin.student.model.dopo.StudentCourseDo;
import com.hhkj.admin.student.model.dopo.StudentCoursePo;
import com.hhkj.admin.student.model.dopo.StudentDo;
import com.hhkj.admin.student.model.dopo.StudentPo;
import com.hhkj.admin.student.model.req.StudentReq;
import com.hhkj.admin.student.service.base.StudentCourseService;
import com.hhkj.admin.student.service.base.StudentService;
import com.hhkj.api.common.session.holder.ApiStudentSessionHolder;
import com.hhkj.api.common.session.holder.model.LoginStudent;
import com.hhkj.api.student.model.InfoRes;
import com.hhkj.api.student.service.biz.ApiStudentBizService;
import com.hhkj.api.student.service.extend.ApiStudentExtendService;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.GlobalCheckException;
import com.ruoyi.common.exception.GlobalException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.framework.login.api.ApiSessionConst;
import com.ruoyi.framework.login.api.ApiSessionUtils;
import com.ruoyi.framework.manager.AsyncManager;
import com.ruoyi.framework.manager.factory.AsyncFactory;
import com.ruoyi.system.service.ISysUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * 学员Service接口
 *
 * @author ruoyi
 * @since 2023-06-08
 */
@Service
public class ApiStudentBizServiceImpl implements ApiStudentBizService {
    @Autowired
    private StudentService studentService;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ApiStudentExtendService apiStudentExtendService;
    @Autowired
    private StudentCourseService studentCourseService;
    @Autowired
    private ISysUserService userService;
    @Autowired
    private RedisCache redisCache;

    @Autowired
    private CourseBankTypeService courseBankTypeService;
    @Autowired
    private CourseService courseService;

    /**
     * 获取当前学员登录信息
     *
     * @return 学员信息
     */
    @Override
    public InfoRes get() {
        LoginStudent loginStudent = ApiStudentSessionHolder.getLoginStudent();
        InfoRes result
                = new InfoRes(loginStudent.getName(), loginStudent.getIdCard(), loginStudent.getCourseLineDate(), loginStudent.getPhone());
        if (ObjectUtil.isNotNull(loginStudent.getCourseLineDate())) {
            Long expiresHourAmount = DateUtil.between(
                    new Date(),
                    DateUtil.endOfDay(loginStudent.getCourseLineDate()),
                    DateUnit.HOUR);
            result.setExpiresHourAmount(expiresHourAmount);
        }
        return result;
    }

    /**
     * 小程序学员登录
     *
     * @param studentReq 登录入参
     * @return 登录信息
     */
    @Override
    public LoginStudent login(Student studentReq) {
        return getLoginStudent(studentReq, true);
    }

    @Override
    public LoginStudent doLogin(Student student) {
        //信息存入,获取token
        LoginStudent loginStudent = storeInfo(student);
        //异步存储登录信息
        AsyncManager.me().execute(AsyncFactory.recordStudentLogininfor(loginStudent.getName(), loginStudent.getId(), loginStudent.getCourseId()));
        return loginStudent;
    }

    /**
     * 登陆后保存信息
     *
     * @param student 登录查询学员信息
     */
    private LoginStudent storeInfo(Student student) {
        String thirdSessionKey = UUID.randomUUID().toString();
        LoginStudent loginStudent = new LoginStudent();
        BeanUtil.copyProperties(student, loginStudent);
        loginStudent.setId(student.getId());
        loginStudent.setName(student.getName());
        // 获取学员创建用户
        SysUser sysUser = userService.selectUserById(student.getCreateBy());
        if (ObjectUtil.isNotNull(sysUser)) {
            loginStudent.setCreateByUserType(sysUser.getUserType());
            loginStudent.setTrainCallBackApi(sysUser.getTrainCallBackApi());
        }
        //关联科目
        StudentReq studentCondition = new StudentReq();
        studentCondition.setId(student.getId());
        studentCondition.setCourseId(student.getCourseId());
        List<StudentPo> studentPos = studentCourseService.selectStudentRelevancyList(studentCondition);
        if (studentPos.size() > 0) {
            StudentPo studentDb = studentPos.get(0);
            BeanUtil.copyProperties(studentDb, loginStudent);
            loginStudent.setCourseLineDate(studentDb.getLineDate());
        }
        String sessionKey = ApiSessionUtils.createSessionKey(student.getId().toString(), thirdSessionKey);
        String cacheKey = ApiSessionUtils.createCacheKey(LoginStudent.class, sessionKey);
        String cacheKeyPrefix = ApiSessionUtils.createCacheKeyPrefix(LoginStudent.class, student.getId().toString());
        //将3rd_session和用户信息存入redis，并设置过期时间
        // String key = ApiSessionConst.SESSION_BEGIN + ":" + student.getId() + ":" + thirdSessionKey;
        //清除已经登陆的学员
        cleanLoginStudent(cacheKeyPrefix);
        //保存当前登录学员到缓存
        redisCache.setCacheObject(cacheKey, loginStudent, ApiSessionConst.SESSION_TIME_OUT, TimeUnit.HOURS);
        loginStudent.setSessionKey(sessionKey);
        return loginStudent;
    }

    /**
     * 清除已经登录的学员
     *
     * @param prefixKey 键前缀
     */
    private void cleanLoginStudent(String prefixKey) {
        Set<String> keys = redisTemplate.keys(prefixKey + "*");
        if (keys != null && keys.size() > 0) {
            redisTemplate.delete(keys);
        }
    }

    /**
     * 小程序学员退出登录
     *
     * @param studentReq 登出入参
     * @return 删除缓存结果
     */
    @Override
    public boolean logout(LoginStudent studentReq) {
        String key = ApiSessionUtils.createCacheKey(LoginStudent.class, studentReq.getSessionKey());
        return Boolean.TRUE.equals(redisTemplate.delete(key));
    }

    /**
     * 校验身份证号密码，并返回（审核通过的）科目列表
     *
     * @param studentReq 传参
     */
    @Override
    public List<StudentPo> listCourse(Student studentReq) {
        return studentService.selectStudentCourseByDo(studentReq);
    }

    @Override
    public boolean saveStudentAndCourse(Student studentReq) {
        Long studentId = saveStudent(studentReq);
        saveStudentCourse(studentReq, studentId);
        return true;
    }

    /**
     *
     */
    @Override
    public List<CoursePo> listFreeCourseByParentId(Long parentId) {
        CourseDo courseDo = new CourseDo();
        courseDo.setParentId(parentId);
        List<CoursePo> coursePoList = courseService.listPoByDo(courseDo);

        return coursePoList;
    }

    @Override
    public LoginStudent loginNew(Student studentReq) {
        return getLoginStudent(studentReq, false);
    }

    public Long saveStudent(Student studentReq) {
        StudentDo studentDo = new StudentDo();
        studentDo.setIdCard(studentReq.getPhone());
        studentService.getPoByDo(studentDo);

        Long defaultUserId = 1L;
        Long studentId = -1L;
        if (studentDo == null) {
            Student student = new Student();
            student.setName(studentReq.getName());
            student.setIdCard(studentReq.getPhone());
            student.setPhone(studentReq.getPhone());
            StudentUtils.encryptPassword(student);
            student.setCreateBy(defaultUserId);
            studentService.save(student);
            studentId = student.getId();
        }else{
            studentId = studentDo.getId();
        }

        return studentId;
    }

    public void saveStudentCourse(Student studentReq, Long studentId) {
        Long defaultUserId = 1L;
        CourseBankTypeDo condition = new CourseBankTypeDo();
        condition.setCourseId(studentReq.getCourseParentId());
        condition.setFreeFlag(1); //免费的才能直接注册，防止别人直接调用该接口注册收费的
        CourseBankTypePo courseBankTypePo = courseBankTypeService.getPoByDo(condition);
        if (courseBankTypePo == null){
            throw new GlobalCheckException(HttpStatus.NOT_FOUND, "课程未找到");
        }

        StudentCourseDo studentCourseDo = new StudentCourseDo();
        studentCourseDo.setStudentId(studentId);
        studentCourseDo.setCourseId(studentReq.getCourseId());
        StudentCoursePo studentCoursePo = studentCourseService.getPoByDo(studentCourseDo);
        if (studentCoursePo != null) {
            throw new GlobalCheckException(HttpStatus.CONFLICT, "学员已注册该课程");
        }

        StudentCourse studentCourse = new StudentCourse();
        studentCourse.setStudentId(studentId);
        studentCourse.setCourseId(studentReq.getCourseId());
        studentCourse.setCourseBankTypeId(courseBankTypePo.getId());
        studentCourse.setStatus(StudentConst.AuditCode.STATUS_PASS.getCode());
        studentCourse.setUnitPayPrice(new BigDecimal(0));
        studentCourse.setCreateBy(defaultUserId);
        Date currentDate = new Date();
        Calendar cal = Calendar.getInstance();
        cal.setTime(currentDate);//设置起时间
        cal.add(Calendar.YEAR, 1);//增加一年
        studentCourse.setStartDate(currentDate);
        studentCourse.setLineDate(cal.getTime());
        studentCourse.setBatchId(-1L);
        studentCourseService.save(studentCourse);
    }

    /**
     * 学员登录
     * @param studentReq
     * @param isNeedCourseId
     * @return
     */
    private LoginStudent getLoginStudent(Student studentReq, boolean isNeedCourseId) {
        //校验账号密码,返回查询信息
        Student student = apiStudentExtendService.verifyCommonInfo(studentReq, isNeedCourseId);
        //校验开始日期、到期日期、是否同一个微信登录
        apiStudentExtendService.verifyInfo(student);
        return this.doLogin(student);
    }
}
